package ch.ethz.fcl.metrobuzz.algorithm.voronoi.Paul;

import java.util.HashSet;
import java.util.List;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.MBContainer;
import ch.ethz.fcl.metrobuzz.controller.MBController;
import ch.ethz.fcl.metrobuzz.controller.external.ActionEvent;
import ch.ethz.fcl.metrobuzz.render.MBRenderer;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.spatialindex.object3d.Point3D;
import ch.ethz.fcl.metrobuzz.tools.MBGL;
import ch.ethz.fcl.metrobuzz.viewer.MBViewer;
import ch.ethz.fcl.metrobuzz.viewer.MBViewer.ProjectionType;

/**
 * Test code of how to work with Paul Chew's voronoi algorithm
 * 
 * @author ZengWei
 * 
 */
public class VoronoiTest {
	private MBContainer container;

	private Triangulation dt; // Delaunay triangulation
	private Triangle initialTriangle; // Initial triangle
	private static float initialSize = 100f; // initial triangle
	private float x = 0, y = 0;

	public static void main(String[] args) {
		new VoronoiTest().run();
	}

	public VoronoiTest() {
		init();
	}

	private void run() {
		while (!Display.isCloseRequested()) {
			GL11.glPushMatrix();
			container.getViewer().update();

			container.getControl().update();

			update();
			render();

			GL11.glPopMatrix();

			Display.update();
			Display.sync(32);
		}
		Display.destroy();
		System.exit(0);
	}

	private void init() {
		initialTriangle = new Triangle(new Pnt(-initialSize, -initialSize),
				new Pnt(initialSize, -initialSize), new Pnt(0, initialSize));
		dt = new Triangulation(initialTriangle);

		container = new MBContainer();

		MBViewer view = new MBViewer(ProjectionType.Perspective, container);

		new MBRenderer(container);

		int screenWidth = Display.getDesktopDisplayMode().getWidth();
		int screenHeight = Display.getDesktopDisplayMode().getHeight();
		view.createDisplay(screenWidth, screenHeight, screenWidth, screenHeight,
				"Paul Voronoi test");
		view.getCamera().initDistance(1.0f);
		view.getCamera().disablePan();

		new MBController(container);
	}

	private void update() {
		ActionEvent action = container.getControl().getMouseListener()
				.getRightMouse();

		if (action.getAction() == ActionEvent.ACTION_DOWN) {
			Point3D clickPoint = container
					.getViewer()
					.getProjection()
					.getWorldCoord(
							new Point2D(action.getEventX(), action.getEventY()),
							0);

			x = clickPoint.getX();
			y = clickPoint.getY();

			dt.delaunayPlace(new Pnt(x, y));
		}
	}

	private void render() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		GL11.glClearColor(1, 1, 1, 1);

		MBGL.enableBlend();

		GL11.glLineWidth(1.0f);

		HashSet<Pnt> done = new HashSet<Pnt>(initialTriangle);
		for (Triangle triangle : dt)
			for (Pnt site : triangle) {
				if (done.contains(site))
					continue;
				done.add(site);
				List<Triangle> list = dt.surroundingTriangles(site, triangle);
				Pnt[] vertices = new Pnt[list.size()];
				int i = 0;
				for (Triangle tri : list)
					vertices[i++] = tri.getCircumcenter();

				GL11.glColor4f(0, 0, 1, 1);
				GL11.glBegin(GL11.GL_LINE_STRIP);
				for (Pnt vertex : vertices)
					GL11.glVertex2d(vertex.coord(0), vertex.coord(1));

				GL11.glVertex2d(vertices[0].coord(0), vertices[0].coord(1));
				GL11.glEnd();

				GL11.glColor4f(1, 0, 0, 1);
				GL11.glPointSize(10);
				GL11.glBegin(GL11.GL_POINTS);
				GL11.glVertex2d(site.coord(0), site.coord(1));
				GL11.glEnd();
			}

		MBGL.disableBlend();
	}
}
